{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python数据模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python风格的纸牌"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "import collections\n",
    "\n",
    "class Deck:\n",
    "    ranks = [str(n) for n in range(2, 11)] + list('JQKA')\n",
    "    suits = ('黑桃', '红桃', '梅花', '方块')\n",
    "    suit_values = {'黑桃':3, '红桃':2, '梅花':1, '方块':0}\n",
    "    Card = collections.namedtuple('Card', ['rank', 'suit'])\n",
    "    \n",
    "    def __init__(self):\n",
    "        self._cards = [self.Card(rank, suit) for suit in self.suits for rank in self.ranks]\n",
    "        \n",
    "    def __len__(self):\n",
    "        return len(self._cards)\n",
    "    \n",
    "    def __getitem__(self, position):\n",
    "        return self._cards[position]\n",
    "    \n",
    "    @staticmethod\n",
    "    def score(card):\n",
    "        rank_value = Deck.ranks.index(card.rank)\n",
    "        return rank_value*len(Deck.suit_values) + Deck.suit_values[card.suit]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "__main__.Card"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Deck.Card"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Card(rank='7', suit='黑桃')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "card1 = Deck.Card('7', '黑桃')\n",
    "card1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "52"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "deck = Deck()\n",
    "len(deck)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Card(rank='2', suit='黑桃')\n",
      "Card(rank='A', suit='方块')\n"
     ]
    }
   ],
   "source": [
    "print(deck[0])\n",
    "print(deck[-1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Card(rank='3', suit='红桃')\n",
      "Card(rank='2', suit='梅花')\n",
      "Card(rank='9', suit='梅花')\n",
      "Card(rank='10', suit='方块')\n",
      "Card(rank='A', suit='黑桃')\n",
      "Card(rank='5', suit='黑桃')\n"
     ]
    }
   ],
   "source": [
    "from random import choice\n",
    "print(choice(deck))\n",
    "print(choice(deck))\n",
    "print(choice(deck))\n",
    "print(choice(deck))\n",
    "print(choice(deck))\n",
    "print(choice(deck))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections.abc import Iterable\n",
    "isinstance(deck, Iterable)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Card(rank='2', suit='黑桃')\n",
      "Card(rank='3', suit='黑桃')\n"
     ]
    }
   ],
   "source": [
    "it = iter(deck)\n",
    "print(next(it))\n",
    "print(next(it))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Deck.Card(rank='2', suit='黑桃') in deck"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Card(rank='2', suit='方块')\n",
      "Card(rank='2', suit='梅花')\n",
      "Card(rank='2', suit='红桃')\n",
      "Card(rank='2', suit='黑桃')\n",
      "Card(rank='3', suit='方块')\n",
      "Card(rank='3', suit='梅花')\n",
      "Card(rank='3', suit='红桃')\n",
      "Card(rank='3', suit='黑桃')\n",
      "Card(rank='4', suit='方块')\n",
      "Card(rank='4', suit='梅花')\n",
      "Card(rank='4', suit='红桃')\n",
      "Card(rank='4', suit='黑桃')\n",
      "Card(rank='5', suit='方块')\n",
      "Card(rank='5', suit='梅花')\n",
      "Card(rank='5', suit='红桃')\n",
      "Card(rank='5', suit='黑桃')\n",
      "Card(rank='6', suit='方块')\n",
      "Card(rank='6', suit='梅花')\n",
      "Card(rank='6', suit='红桃')\n",
      "Card(rank='6', suit='黑桃')\n",
      "Card(rank='7', suit='方块')\n",
      "Card(rank='7', suit='梅花')\n",
      "Card(rank='7', suit='红桃')\n",
      "Card(rank='7', suit='黑桃')\n",
      "Card(rank='8', suit='方块')\n",
      "Card(rank='8', suit='梅花')\n",
      "Card(rank='8', suit='红桃')\n",
      "Card(rank='8', suit='黑桃')\n",
      "Card(rank='9', suit='方块')\n",
      "Card(rank='9', suit='梅花')\n",
      "Card(rank='9', suit='红桃')\n",
      "Card(rank='9', suit='黑桃')\n",
      "Card(rank='10', suit='方块')\n",
      "Card(rank='10', suit='梅花')\n",
      "Card(rank='10', suit='红桃')\n",
      "Card(rank='10', suit='黑桃')\n",
      "Card(rank='J', suit='方块')\n",
      "Card(rank='J', suit='梅花')\n",
      "Card(rank='J', suit='红桃')\n",
      "Card(rank='J', suit='黑桃')\n",
      "Card(rank='Q', suit='方块')\n",
      "Card(rank='Q', suit='梅花')\n",
      "Card(rank='Q', suit='红桃')\n",
      "Card(rank='Q', suit='黑桃')\n",
      "Card(rank='K', suit='方块')\n",
      "Card(rank='K', suit='梅花')\n",
      "Card(rank='K', suit='红桃')\n",
      "Card(rank='K', suit='黑桃')\n",
      "Card(rank='A', suit='方块')\n",
      "Card(rank='A', suit='梅花')\n",
      "Card(rank='A', suit='红桃')\n",
      "Card(rank='A', suit='黑桃')\n"
     ]
    }
   ],
   "source": [
    "for card in sorted(deck, key=Deck.score):\n",
    "    print(card)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用特殊方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "from math import hypot\n",
    "\n",
    "class Vector:\n",
    "    def __init__(self, x, y):\n",
    "        self.x = x\n",
    "        self.y = y\n",
    "        \n",
    "    def __repr__(self):\n",
    "        return 'Vector({x}, {y})'.format(x = self.x, y = self.y)\n",
    "    \n",
    "    def __abs__(self):\n",
    "        return hypot(self.x, self.y)\n",
    "    \n",
    "    def __mul__(self, scalar):\n",
    "        return Vector(self.x*scalar, self.y*scalar)\n",
    "    \n",
    "    def __add__(self, other):\n",
    "        x = self.x + other.x\n",
    "        y = self.y + other.y\n",
    "        return Vector(x, y)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "v = Vector(3,4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Vector(3, 4)"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Vector(3, 4)\n"
     ]
    }
   ],
   "source": [
    "print(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5.0"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "abs(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Vector(9, 12)"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v*3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Vector(4, 5)"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "o = Vector(1, 1)\n",
    "v+o"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
